﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Linq;

namespace AvalonDock
{
    /// <summary>
    /// Logical tree extensions.
    /// </summary>
    internal static class LogicalTreeExtensions
    {
        /// <summary>
        /// Gets the logical children.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns></returns>
        public static IEnumerable<DependencyObject> GetLogicalChildren(this DependencyObject dependencyObject)
        {
            return LogicalTreeHelper.GetChildren(dependencyObject).Cast<DependencyObject>();
        }

        /// <summary>
        /// Gets the logical parent.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns></returns>
        public static DependencyObject GetLogicalParent(this DependencyObject dependencyObject)
        {
            return LogicalTreeHelper.GetParent(dependencyObject);
        }

        /// <summary>
        /// Gets the visual children.
        /// </summary>
        /// <typeparam name="TType">The type of the type.</typeparam>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>The visual children of the dependency object.</returns>
        public static List<TType> GetLogicalDescendants<TType>(this DependencyObject dependencyObject) where TType : DependencyObject
        {
            var children = new List<TType>();
            foreach(var child in dependencyObject.GetLogicalChildren())
            {

                children.AddRange(child.GetLogicalDescendants<TType>());
                if (child is TType)
                {
                    children.Add((TType)child);
                }
            }

            return children;
        }

        /// <summary>
        /// Gets the visual parents.
        /// </summary>
        /// <typeparam name="TType">The type of the type.</typeparam>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>The visual parents of the dependency object.</returns>
        public static List<TType> GetLogicalAncestors<TType>(this DependencyObject dependencyObject) where TType : DependencyObject
        {
            var parants = new List<TType>();
            var parent = LogicalTreeHelper.GetParent(dependencyObject);
            if (parent == null)
            {
                return new List<TType>();
            }

            parants.AddRange(parent.GetLogicalAncestors<TType>());
            if (parent is TType)
            {
                parants.Add((TType)parent);
            }

            return parants;
        }

        /// <summary>
        /// Gets the nearest visual parent.
        /// </summary>
        /// <typeparam name="TType">The type of the type.</typeparam>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>The visual parent of the dependency object.</returns>
        public static TType GetNearestLogicalAncestor<TType>(this DependencyObject dependencyObject) where TType : DependencyObject
        {
            if (dependencyObject == null)
            {
                return null;
            }

            var parent = LogicalTreeHelper.GetParent(dependencyObject);
            if (parent is TType)
            {
                return (TType)parent;
            }

            return GetNearestLogicalAncestor<TType>(parent);
        }
    }
}
